package com.yourenbang.lingyun.transaction.web.service.impl.pay.withdraw;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.yourenbang.lingyun.constants.BizCodeMessages;
import com.yourenbang.lingyun.constants.Constant;
import com.yourenbang.lingyun.constants.DeleteFlag;
import com.yourenbang.lingyun.constants.enums.ChannelIdEnums;
import com.yourenbang.lingyun.constants.enums.PlatNoEnums;
import com.yourenbang.lingyun.constants.enums.WithDrawStatusEnum;
import com.yourenbang.lingyun.constants.enums.fund.AccountMainJournalType;
import com.yourenbang.lingyun.constants.enums.fund.AccountType;
import com.yourenbang.lingyun.constants.enums.pay.PayFromEnum;
import com.yourenbang.lingyun.constants.enums.pay.PayTypeEnum;
import com.yourenbang.lingyun.constants.enums.table.FundAccountWithdrawPaymentBillEnum;
import com.yourenbang.lingyun.constants.enums.table.FundAccountWithdrawPaymentEnum;
import com.yourenbang.lingyun.constants.enums.table.FundWithdrawDebitListEnum;
import com.yourenbang.lingyun.core.exception.BizRuntimeException;
import com.yourenbang.lingyun.core.exception.UserBizException;
import com.yourenbang.lingyun.core.message.Result;
import com.yourenbang.lingyun.core.util.AssertUtils;
import com.yourenbang.lingyun.core.util.BizAssertUtils;
import com.yourenbang.lingyun.core.util.ExportExcelUtils;
import com.yourenbang.lingyun.core.util.KLog;
import com.yourenbang.lingyun.core.util.date.DateFormat;
import com.yourenbang.lingyun.core.util.date.LocalDateUtils;
import com.yourenbang.lingyun.core.util.http.HttpClientUtil;
import com.yourenbang.lingyun.domain.*;
import com.yourenbang.lingyun.mapper.CreditBuyOrderMapper;
import com.yourenbang.lingyun.mapper.FundWithdrawDebitListMapper;
import com.yourenbang.lingyun.mapper.UserBankCardMapper;
import com.yourenbang.lingyun.mapper.UserBaseMapper;
import com.yourenbang.lingyun.transaction.config.AcmTransactionParams;
import com.yourenbang.lingyun.transaction.constant.ChangeTypeConstant;
import com.yourenbang.lingyun.transaction.exception.WichdrawFailException;
import com.yourenbang.lingyun.transaction.exception.WichdrawWaitException;
import com.yourenbang.lingyun.transaction.mapper.TransactionFundAccountWithdrawPaymentBillMapper;
import com.yourenbang.lingyun.transaction.mapper.TransactionFundAccountWithdrawPaymentMapper;
import com.yourenbang.lingyun.transaction.mapper.TransactionPayTypeMapper;
import com.yourenbang.lingyun.transaction.util.HttpHolderUtil;
import com.yourenbang.lingyun.transaction.web.domain.dto.ChangeFundAccountV2DTO;
import com.yourenbang.lingyun.transaction.web.domain.dto.pay.FundPayApiDTO;
import com.yourenbang.lingyun.transaction.web.domain.po.FundAccountWithdrawPayment;
import com.yourenbang.lingyun.transaction.web.domain.vo.JournalInfoVO;
import com.yourenbang.lingyun.transaction.web.domain.vo.fund.AccountQueryGroupVO;
import com.yourenbang.lingyun.transaction.web.domain.vo.pay.FundPayApiVO;
import com.yourenbang.lingyun.transaction.web.service.CommonService;
import com.yourenbang.lingyun.transaction.web.service.fund.FundService;
import com.yourenbang.lingyun.transaction.web.service.pay.withdraw.WithdrawPayService;
import com.yourenbang.lingyun.transaction.web.service.pay.withdraw.WithdrawService;
import com.yourenbang.lingyun.transaction.web.service.yxy.YxyWithdrawalService;
import com.yourenbang.transaction.api.model.dto.pay.WithDrawParamsDTO;
import com.yourenbang.transaction.api.model.dto.pay.WithDrawVO;
import com.yourenbang.transaction.api.model.vo.FundPayBusVO;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.*;

@Slf4j
@Service("merWithdrawService")
public class WithdrawServiceImpl implements WithdrawService {

    @Autowired
    private TransactionFundAccountWithdrawPaymentBillMapper transactionFundAccountWithdrawPaymentBillMapper;
    @Autowired
    private TransactionFundAccountWithdrawPaymentMapper fundAccountWithdrawPaymentMapper;
    @Autowired
    private CommonService commonService;
    @Autowired
    private UserBaseMapper userBaseMapper;
    @Autowired
    private FundService fundService;
    @Autowired
    private WithdrawPayService withdrawPayService;
    @Autowired
    private TransactionPayTypeMapper transactionPayTypeMapper;
    @Autowired
    private YxyWithdrawalService yxyWithdrawalService;
    @Autowired
    private FundWithdrawDebitListMapper fundWithdrawDebitListMapper;
    @Autowired
    private AcmTransactionParams acmTransactionParams;
    @Autowired
    private UserBankCardMapper userBankCardMapper;
    @Resource
    private CreditBuyOrderMapper creditBuyOrderMapper;

    @Override
    public Result<WithDrawVO> withdrawV2(WithDrawParamsDTO withDrawParamsDTO) {

        //有效性检查
        Result result = preCheck(withDrawParamsDTO);
        AssertUtils.isTrue(result.isSuccess(), result.getDesc());

        // 代付有效性检查,降低回滚概率
        result = withdrawPayService.withDrawPreCheck(withDrawParamsDTO.getWithdrawPayType(), withDrawParamsDTO.getPlatNo());
        AssertUtils.isTrue(result.isSuccess(), result.getDesc());

        // 如果是银行卡提现,需修改实际发起代付的类型
        WithDrawParamsDTO realWithDrawParamsDTO = getRealWithDrawParamsDTO(withDrawParamsDTO);

        UserBase userBase = userBaseMapper.selectByPrimaryKey(realWithDrawParamsDTO.getUserBaseId());
        AssertUtils.isNotNull(userBase, BizCodeMessages.TERMINAL_TRANSFER_USER_QUERY_NO);

        //创建提现订单
        FundAccountWithdrawPayment withdrawPayment = createWithdrawPaymentOrder(userBase, realWithDrawParamsDTO);
        if (!FundAccountWithdrawPaymentEnum.SettleTypeEnum.D0.isEquals(withdrawPayment.getSettleType())) {
            //仅支持D0交易
            throw new UserBizException(BizCodeMessages.PARAMS_ERROR, "不支持非D0提现");
        }

        //调用服务校验签约状态
        String httpPostRequest = "";
        String jumpUrl = "https://static.d.mugeyrb.com/app/yrb/qianyue.html";
        String postUrl = "https://testapi.mugeyrb.com/transaction/wallet/withdraw/check?userBaseId="+realWithDrawParamsDTO.getUserBaseId();
        if (commonService.isProd()) {
            postUrl = "http://172.17.187.6:8886/transaction/wallet/withdraw/check?userBaseId="+realWithDrawParamsDTO.getUserBaseId();
            jumpUrl = "https://static.mugeyrb.com/app/yrb/qianyue.html";
        }
        try {
            httpPostRequest = HttpClientUtil.httpGetRequest(postUrl);
        } catch (Exception e) {
            e.printStackTrace();
        }
        log.info("提现签约状态校验,出参：{}", httpPostRequest);
        HashMap map = JSONObject.parseObject(httpPostRequest, HashMap.class);
        if(!map.get("code").toString().equals("3")){
            throw new UserBizException(BizCodeMessages.VALIDATOR_WITHDRAWED, "请先完成签约再提现---"+jumpUrl);
        }

        try {

            //提现冻结资金 记录账单
            depositWithdrawFund(withdrawPayment, realWithDrawParamsDTO);

        } catch (UserBizException e) {

            KLog.warn("【凌云提现】提现失败, 可提余额冻结失败,{}", e.getErrorCode(), e);
            //提现订单更新为失败
            withdrawPayment.setWithdrawStatus(WithDrawStatusEnum.WITHDRAW_STATUS_FAIL.getCode());
            withdrawPayment.setErrors(e.getMessage());
            int upWith = fundAccountWithdrawPaymentMapper.updateById(withdrawPayment);
            BizAssertUtils.assertOne(upWith, "修改提现状态失败");
            return Result.builder().fail(BizCodeMessages.UNKNOWN_ERROR, e.getErrorMessage());

        } catch (Exception e) {

            KLog.error("【凌云提现】提现异常, 可提余额冻结失败,{}", e.getMessage());
            //提现订单更新为失败
            withdrawPayment.setWithdrawStatus(WithDrawStatusEnum.WITHDRAW_STATUS_FAIL.getCode());
            withdrawPayment.setErrors(e.getMessage());
            int upWith = fundAccountWithdrawPaymentMapper.updateById(withdrawPayment);
            BizAssertUtils.assertOne(upWith, "修改提现状态失败");
            return Result.builder().fail(BizCodeMessages.UNKNOWN_ERROR, e.getMessage());

        }


        FundAccountWithdrawPayment upWithPay2 = new FundAccountWithdrawPayment(realWithDrawParamsDTO.getPlatNo());
        upWithPay2.setFundAccountWithdrawPaymentId(withdrawPayment.getFundAccountWithdrawPaymentId());

        try {

            // 发起代付
            doWithdrawRequest(realWithDrawParamsDTO, withdrawPayment);

        } catch (BizRuntimeException e) {

            KLog.warn("【凌云提现】提现失败, 业务失败,{}", e.getMessage());
            upWithPay2.setThirdRequestStatus(FundAccountWithdrawPayment.THIRDREQUESTSTATUS_SUCC);
            upWithPay2.setErrors(e.getMessage());
            upWithPay2.setWithdrawStatus(WithDrawStatusEnum.WITHDRAW_STATUS_FAIL.getCode());
            Integer upPay = fundAccountWithdrawPaymentMapper.updateById(upWithPay2);
            BizAssertUtils.assertOne(upPay, "修改提现状态失败");

            BizCodeMessages bizCodeMessages = BizCodeMessages.getBizCodeMessages(e.getErrorCode());
            return Result.builder().fail(Objects.isNull(bizCodeMessages) ? BizCodeMessages.UNKNOWN_ERROR : bizCodeMessages, e.getErrorMessage());

        } catch (WichdrawFailException e) {

            KLog.warn("【凌云提现】提现失败, 通道返回失败,{}", e.getMessage(), e);
            upWithPay2.setThirdRequestStatus(FundAccountWithdrawPayment.THIRDREQUESTSTATUS_SUCC);
            upWithPay2.setErrors(e.getMessage());
            upWithPay2.setWithdrawStatus(WithDrawStatusEnum.WITHDRAW_STATUS_FAIL.getCode());
            Integer upPay = fundAccountWithdrawPaymentMapper.updateById(upWithPay2);
            BizAssertUtils.assertOne(upPay, "修改提现状态失败");

            //归还冻结金额
            fundService.cancelByFundAccountWithdrawPaymentId(withdrawPayment.getFundAccountWithdrawPaymentId(), realWithDrawParamsDTO.getPlatNo());

            return Result.builder().fail(BizCodeMessages.UNKNOWN_ERROR, "请根据短信完成（福穗）签约");

        } catch (Exception e) {

            KLog.error("【凌云提现】异常,{}", e.getMessage(), e);
            upWithPay2.setThirdRequestStatus(FundAccountWithdrawPayment.THIRDREQUESTSTATUS_ERROR);
            upWithPay2.setErrors(e.getMessage());
            upWithPay2.setWithdrawStatus(WithDrawStatusEnum.WITHDRAW_STATUS_FAIL.getCode());
            Integer upPay = fundAccountWithdrawPaymentMapper.updateById(upWithPay2);
            BizAssertUtils.assertOne(upPay, "修改提现状态失败");

            return Result.builder().fail(BizCodeMessages.UNKNOWN_ERROR, "提现失败");

        }


        WithDrawVO drawVO = new WithDrawVO();
        drawVO.setAmount(withdrawPayment.getAmount());
        drawVO.setInAmount(withdrawPayment.getInAmount());
        drawVO.setFee(withdrawPayment.getFee());
        drawVO.setThirdAccount(realWithDrawParamsDTO.getThirdAccount());
        drawVO.setOrderSn(withdrawPayment.getOrderSn());

        return Result.builder().success(drawVO);
    }

    private WithDrawParamsDTO getRealWithDrawParamsDTO(WithDrawParamsDTO withDrawParamsDTO) {

        WithDrawParamsDTO realWithDrawParamsDTO = new WithDrawParamsDTO();
        BeanUtils.copyProperties(withDrawParamsDTO, realWithDrawParamsDTO);

        if (PayTypeEnum.BANK_CARD_PAY.isEquals(withDrawParamsDTO.getWithdrawPayType())) {
            // 如果是银行卡提现,选择当前有效的代付渠道
            PayType payType = transactionPayTypeMapper.getBankCardPayTypeByPayFrom(PayFromEnum.yxy_withdraw_ally_all.getCode(), withDrawParamsDTO.getPlatNo());
            if (Objects.isNull(payType)) {
                throw new UserBizException(BizCodeMessages.WITHDRAW_PAY_TYPE_OFF);
            }
            realWithDrawParamsDTO.setWithdrawPayType(payType.getCode());
        }

        return realWithDrawParamsDTO;

    }

    private Result preCheck(WithDrawParamsDTO withDrawParamsDTO) {

        //防重复提交
        if (commonService.repeatSubmit("merWithdraw:" + withDrawParamsDTO.getUserBaseId())) {
            return Result.builder().fail(BizCodeMessages.CORE_API_REQUEST_LIMITED);
        }

        //是否在黑名单
        if (!yxyWithdrawalService.getYxyWithdrawalFlag(withDrawParamsDTO.getUserBaseId())) {
            return Result.builder().fail(BizCodeMessages.TRANSACTION_STAFF_BAN_WITHDRAW, "您已被暂时关闭提现功能，如有问题可联系您的上级盟友");
        }

        //是否负债
        if (isWithdrawDebitFlag(withDrawParamsDTO.getUserBaseId())) {
            return Result.builder().fail(BizCodeMessages.TRANSACTION_IN_FUND_WITHDRAW_DEBIT, "您在提现负债名单中，暂时关闭提现功能，详情请咨询在线客服");
        }

        if (!PlatNoEnums.YXY.isEquals(withDrawParamsDTO.getPlatNo())) {
            return Result.builder().fail(BizCodeMessages.CORE_API_REQUEST_LIMITED, "接口限制");
        }

        //判断实名状态
        if (userUnCheck(withDrawParamsDTO.getUserBaseId())) {
            return Result.builder().fail(BizCodeMessages.USER_REAL_NAME);
        }
        //商户账户不判断赊购
        if (creditBuyOrderCheck(withDrawParamsDTO.getUserBaseId()) && !StringUtils.equalsAny(withDrawParamsDTO.getToAccountType(),
                AccountType.MER.getFullCode(PlatNoEnums.YXY.getCode()) + "", AccountType.MERCHANT_FROM_BOSS.getFullCode(PlatNoEnums.YXY.getCode()) + "")) {
            return Result.builder().fail(BizCodeMessages.TRANSACTION_IN_FUND_WITHDRAW_DEBIT, "您有待还的赊购订单，不允许提现");
        }

        return Result.builder().success();
    }

    private boolean creditBuyOrderCheck(String userBaseId) {
        //是否有赊购订单
        CreditBuyOrderExample creditBuyOrderExample = new CreditBuyOrderExample();
        creditBuyOrderExample.createCriteria().andUserBaseIdEqualTo(userBaseId);
        List<CreditBuyOrder> creditBuyOrderList = creditBuyOrderMapper.selectByExample(creditBuyOrderExample);
        if (org.apache.commons.collections4.CollectionUtils.isNotEmpty(creditBuyOrderList)) {
            for (CreditBuyOrder creditBuyOrder : creditBuyOrderList) {
                if (creditBuyOrder.getTotalAmount().compareTo(creditBuyOrder.getAlreadyReturn()) > 0
                        && creditBuyOrder.getBanWithdrawal().intValue() == 10) {
                    return true;
                }
            }
        }
        return false;
    }
    /**
     * 发起提现请求
     *
     * @param withDrawParamsDTO 提现参数
     * @param withdrawPayment   提现订单参数实体
     */
    private void doWithdrawRequest(WithDrawParamsDTO withDrawParamsDTO, FundAccountWithdrawPayment withdrawPayment) {

        LocalDateTime now = LocalDateTime.now();

        FundPayApiDTO apiDTO = new FundPayApiDTO();
        apiDTO.setPlatNo(withDrawParamsDTO.getPlatNo());
        apiDTO.setUserBaseId(withDrawParamsDTO.getUserBaseId());
        apiDTO.setPayFrom(PayFromEnum.yxy_withdraw_ally_all.getCode());
        apiDTO.setPayType(withDrawParamsDTO.getWithdrawPayType());
        apiDTO.setOrderNo(withdrawPayment.getOrderSn());
        apiDTO.setAccountNo(withdrawPayment.getThirdAccount());
        apiDTO.setName(withdrawPayment.getUserName());
        apiDTO.setIdCard(withdrawPayment.getIdNumber());
        apiDTO.setPhone(withdrawPayment.getPhone());
        apiDTO.setAmt(withdrawPayment.getInAmount());
        apiDTO.setFee(withdrawPayment.getFee());

        //请求提现
        FundPayApiVO fundPayApiVO = withdrawPayService.withDraw(apiDTO);

        //拼接更新参数
        FundAccountWithdrawPayment upWithPay = new FundAccountWithdrawPayment(withDrawParamsDTO.getPlatNo());
        upWithPay.setFundAccountWithdrawPaymentId(withdrawPayment.getFundAccountWithdrawPaymentId());
        upWithPay.setThirdRequestDesc(apiDTO.toJSON());
        upWithPay.setRequestDate(now);
        upWithPay.setPayChannelId(fundPayApiVO.getPayChannelId());
        upWithPay.setThirdOrderId(fundPayApiVO.getThirdOrderId());
        upWithPay.setThirdPayStatus(fundPayApiVO.getThirdPayStatus());
        upWithPay.setThirdPayStatusDesc(fundPayApiVO.getThirdPayStatusDesc());
        upWithPay.setContext(fundPayApiVO.getContext());
        upWithPay.setThirdRequestStatus(FundAccountWithdrawPayment.THIRDREQUESTSTATUS_SUCC);
        upWithPay.setSuccessDate(now);
        upWithPay.setWithdrawStatus(WithDrawStatusEnum.WITHDRAW_STATUS_WAIT.getCode());
        Integer upPay = fundAccountWithdrawPaymentMapper.updateById(upWithPay);
        BizAssertUtils.assertOne(upPay, "修改提现状态失败");

    }

    /**
     * 冻结资金 记录账单
     */
    private void depositWithdrawFund(FundAccountWithdrawPayment withdrawPayment, WithDrawParamsDTO withDrawParamsDTO) {


        Integer accountTypeInt = Integer.valueOf(withDrawParamsDTO.getToAccountType());
        AccountType toAccountType = AccountType.getAccountTypeByFullCode(accountTypeInt);
        AccountMainJournalType accountMainJournalType;


        if (AccountType.ALLY_V2.isEquals(toAccountType)) {
            accountMainJournalType = AccountMainJournalType.ALLY_V2_OUT;
        } else if (AccountType.ALLY_FROM_BOSS.isEquals(toAccountType)) {
            accountMainJournalType = AccountMainJournalType.ALLY_V2_OUT;
        } else if (AccountType.MERCHANT_FROM_BOSS.isEquals(toAccountType)) {
            accountMainJournalType = AccountMainJournalType.MERCHANT_OUT;
        } else {
            throw new UserBizException(BizCodeMessages.TRANSACTION_ACCOUNT_TYPE_NONE, "资金账户类型异常");
        }

        JournalInfoVO journalInfo = ChangeTypeConstant.getDepositJournalTypeV2(toAccountType, accountMainJournalType);

        ChangeFundAccountV2DTO changeFundAccountV2DTO = new ChangeFundAccountV2DTO();
        changeFundAccountV2DTO.setChannelId(ChannelIdEnums.no.getCode());
        changeFundAccountV2DTO.setPlatNo(withDrawParamsDTO.getPlatNo());
        changeFundAccountV2DTO.setUserBaseId(withDrawParamsDTO.getUserBaseId());
        changeFundAccountV2DTO.setChangeAmount(withdrawPayment.getAmount());
        changeFundAccountV2DTO.setOrderNo(withdrawPayment.getOrderSn());
        changeFundAccountV2DTO.setJournalInfo(journalInfo);


        //可提余额冻结
        Result<FundPayBusVO> busResult = fundService.deposit(changeFundAccountV2DTO);

        FundPayBusVO busVO = busResult.getData();
        withdrawPayment.setFundAccountChangePlanId(busVO.getFundAccountChangePlanId());
        withdrawPayment.setFundAccountId(busVO.getFundAccountId());
        withdrawPayment.setInAmount(busVO.getInAmount());
        withdrawPayment.setFee(busVO.getFee());

        if (!busResult.isSuccess()) {
            KLog.info("【凌云提现】可提余额冻结未成功, 调用返回:{}, 入参:{}", JSON.toJSONString(busResult), withDrawParamsDTO.toJSON());

            //提现订单更新为失败
            withdrawPayment.setWithdrawStatus(WithDrawStatusEnum.WITHDRAW_STATUS_FAIL.getCode());
            withdrawPayment.setErrors(busResult.getDesc());
            int upWith = fundAccountWithdrawPaymentMapper.updateById(withdrawPayment);
            BizAssertUtils.assertOne(upWith, "修改提现状态失败");
            throw new UserBizException(BizCodeMessages.UNKNOWN_ERROR, busResult.getDesc());
        }

        int upWith = fundAccountWithdrawPaymentMapper.updateById(withdrawPayment);

        BizAssertUtils.assertOne(upWith, "修改提现状态失败");

    }

    /**
     * 创建提现订单
     */
    private FundAccountWithdrawPayment createWithdrawPaymentOrder(UserBase userBase, WithDrawParamsDTO withDrawParamsDTO) {

        BigDecimal amount = new BigDecimal(withDrawParamsDTO.getAmt());
        //生成订单号
        String orderNo = WithdrawAccountConfig.genOrderNo(withDrawParamsDTO.getToAccountType());

        FundAccountWithdrawPayment withdrawPayment = new FundAccountWithdrawPayment(withDrawParamsDTO.getPlatNo());
        withdrawPayment.setOrderSn(orderNo);
        withdrawPayment.setAmount(amount);
        withdrawPayment.setWithdrawStatus(WithDrawStatusEnum.WITHDRAW_STATUS_INIT.getCode());
        withdrawPayment.setPayGetway(withDrawParamsDTO.getWithdrawPayType());
        // 从哪个资金账户类型提现
        withdrawPayment.setWithdrawType(withDrawParamsDTO.getToAccountType());
        withdrawPayment.setThirdAccount(withDrawParamsDTO.getThirdAccount());
        withdrawPayment.setPhone(userBase.getPhone());
        withdrawPayment.setUserName(userBase.getUserName());
        withdrawPayment.setIdNumber(userBase.getIdNumber());
        withdrawPayment.setBatchNumber(DateFormat.DATE_COMPACT.format(LocalDateTime.now()));

        //判断开启t1则设置t1
        JSONObject withdrawalT1Flag = JSON.parseObject(acmTransactionParams.getWithdrawalT1Flag());
        if (Boolean.TRUE.equals(withdrawalT1Flag.getBoolean(String.valueOf(withDrawParamsDTO.getPlatNo())))) {
            withdrawPayment.setSettleType(FundAccountWithdrawPaymentEnum.SettleTypeEnum.T1.getCode());
        } else {
            withdrawPayment.setSettleType(FundAccountWithdrawPaymentEnum.SettleTypeEnum.D0.getCode());
        }

        //判断是否单独配置
        JSONObject settleConfigJson = JSON.parseObject(acmTransactionParams.getWithdrawalSettleConfig());
        if (StringUtils.isNotBlank(settleConfigJson.getString(userBase.getUserBaseId()))) {
            log.info("提现日结配置:{},short:{}", settleConfigJson.getString(userBase.getUserBaseId()),
                    settleConfigJson.getShort(userBase.getUserBaseId()));
            withdrawPayment.setSettleType(settleConfigJson.getShort(userBase.getUserBaseId()));
        }

        int inWith = fundAccountWithdrawPaymentMapper.insert(withdrawPayment);
        BizAssertUtils.assertOne(inWith, "更新提现记录失败");

        return withdrawPayment;
    }


    /**
     * 提现回调（post请求,参数放body）
     *
     * @param withdrawPayType 提现支付类型
     * @param param           body参数
     */
    @Override
    public boolean fundPayNoticeBody(String withdrawPayType, String param) {

        KLog.info("【提现回调】fundPayNoticeBody:{}, 入参:{}", withdrawPayType, param);

        try {

            //解密回调内容,并获得支付信息
            Result<FundAccountWithdrawPayment> withdrawPaymentResult = withdrawPayService.withDrawNoticeBody(withdrawPayType, param);

            //退款处理
            if (withdrawPaymentResult.isEquals(BizCodeMessages.TRANSACTION_WITHDRAW_FAIL)) {

                FundAccountWithdrawPayment fundAccountWithdrawPayment = withdrawPaymentResult.getData();

                // 明确失败,退还用户资金
                fundService.cancelByFundAccountWithdrawPaymentId(fundAccountWithdrawPayment.getFundAccountWithdrawPaymentId(), PlatNoEnums.YXY.getCode());

                // 标记支付失败
                FundAccountWithdrawPayment upWithPay = new FundAccountWithdrawPayment(PlatNoEnums.YXY.getCode());
                upWithPay.setFundAccountWithdrawPaymentId(fundAccountWithdrawPayment.getFundAccountWithdrawPaymentId());
                upWithPay.setThirdRequestStatus(FundAccountWithdrawPayment.THIRDREQUESTSTATUS_SUCC);
                upWithPay.setErrors(withdrawPaymentResult.getDesc());
                upWithPay.setWithdrawStatus(WithDrawStatusEnum.WITHDRAW_STATUS_FAIL.getCode());
                fundAccountWithdrawPaymentMapper.updateById(upWithPay);

                KLog.warn("【提现回调】提现失败, 代付打款失败,已退款处理");

                return true;
            }

            if (withdrawPaymentResult.isEquals(BizCodeMessages.TRANSACTION_WITHDRAW_PROCESS)) {
                return true;
            }

            if (!withdrawPaymentResult.isSuccess()) {
                return true;
            }

            //成功处理
            withdrawFundProcess(withdrawPaymentResult.getData());
            return true;

        } catch (WichdrawFailException e) {

            KLog.info("【提现回调】接口明确返回失败, 不做处理, withdrawPayType:{}, 入参:{}", withdrawPayType, param);
            return true;

        } catch (WichdrawWaitException e) {

            KLog.info("【提现回调】接口返回处理中, 不做处理, withdrawPayType:{}, 入参:{}", withdrawPayType, param);
            return true;

        } catch (BizRuntimeException e) {

            KLog.warn("【提现回调】业务异常:{}, 不做处理, withdrawPayType:{}, 入参:{}", e.getErrorMessage(), withdrawPayType, param);

        } catch (Exception e) {

            KLog.error("【提现回调】未知异常:{}, 不做处理, withdrawPayType:{}, 入参:{}", e.getMessage(), withdrawPayType, param);

        }

        return false;
    }

    /**
     * 提现回调（post请求,参数放body）
     *
     * @param withdrawPayType 提现支付类型
     * @param param           param参数
     */
    @Override
    public void fundPayNoticeParam(String withdrawPayType, Map<String, String> param) {
        KLog.info("【提现回调】withdrawPayType:{}, 入参:{}", withdrawPayType, param);
        try {

            FundAccountWithdrawPayment payment = withdrawPayService.withDrawNoticeParam(withdrawPayType, param);
            //成功处理
            withdrawFundProcess(payment);

        } catch (WichdrawFailException e) {
            KLog.info("【提现回调】接口明确返回失败, 不做处理, withdrawPayType:{}, 入参:{}", withdrawPayType, param);
        } catch (WichdrawWaitException e) {
            KLog.info("【提现回调】接口返回处理中, 不做处理, withdrawPayType:{}, 入参:{}", withdrawPayType, param);
        } catch (BizRuntimeException e) {
            KLog.warn("【提现回调】业务异常:{}, 不做处理, withdrawPayType:{}, 入参:{}", e.getErrorMessage(), withdrawPayType, param);
        } catch (Exception e) {
            KLog.error("【提现回调】未知异常:{}, 不做处理, withdrawPayType:{}, 入参:{}", e.getMessage(), withdrawPayType, param);
        }
    }

    /**
     * 提现回调 处理
     *
     * @param payment 提现订单
     */
    private void withdrawFundProcess(FundAccountWithdrawPayment payment) {

        //状态检查
        if (payment.getWithdrawStatus().equals(WithDrawStatusEnum.WITHDRAW_STATUS_SUCCESS.getCode())) {
            KLog.info("【提现回调】原订单已成功, 无需处理,提现订单:{}", payment.toJSON());
            return;
        }

        FundAccountWithdrawPayment upWithPay = new FundAccountWithdrawPayment(payment.getPlatNo());
        upWithPay.setFundAccountWithdrawPaymentId(payment.getFundAccountWithdrawPaymentId());
        upWithPay.setWithdrawStatus(WithDrawStatusEnum.WITHDRAW_STATUS_SUCCESS.getCode());   //提现成功
        upWithPay.setUpdateTime(LocalDateTime.now());
        Integer upPay = fundAccountWithdrawPaymentMapper.updateById(upWithPay);
        BizAssertUtils.assertOne(upPay, "修改提现订单失败");

        //扣掉冻结金额
        fundService.undepositByFundAccountWithdrawPaymentId(payment.getFundAccountWithdrawPaymentId(), payment.getPlatNo());

        //更新日结账单表成功笔数
        if (StringUtils.isNotBlank(payment.getBatchNumber()) && FundAccountWithdrawPaymentEnum.SettleTypeEnum.T1.isEquals(payment.getSettleType())) {

            Short payChannelType = PayTypeEnum.ALIPAY.isEquals(payment.getPayGetway()) ? FundAccountWithdrawPaymentBillEnum.PayChannelTypeEnum.ALIPAY.getCode()
                    : FundAccountWithdrawPaymentBillEnum.PayChannelTypeEnum.BANK_CARD.getCode();

            transactionFundAccountWithdrawPaymentBillMapper.updateActualCount(payment.getBatchNumber(),
                    payChannelType, payment.getPlatNo(), payment.getInAmount());
        }

    }

    @Override
    public void withdrawSign(String param) {
        withdrawPayService.withdrawSigne(param);
    }

    @Override
    public void getFuSuiOrderEvidence(String orderNo) {
        FundAccountWithdrawPayment fundAccountWithdrawPayment = fundAccountWithdrawPaymentMapper.findByOrderSn(PlatNoEnums.YXY.getCode(), orderNo);
        List<HashMap<String, Object>> getOrderDTOS = new ArrayList<>();
        HashMap<String, Object> jOrder = new HashMap<>();
        jOrder.put("number", "1");
        jOrder.put("name", fundAccountWithdrawPayment.getUserName());
        jOrder.put("phone", fundAccountWithdrawPayment.getPhone());
        jOrder.put("idCard", StringUtils.upperCase(fundAccountWithdrawPayment.getIdNumber()));
        jOrder.put("accountNo", fundAccountWithdrawPayment.getThirdAccount());
        jOrder.put("amt", fundAccountWithdrawPayment.getAmount().toPlainString());
        jOrder.put("time", LocalDateUtils.formatByDefaultFormat(fundAccountWithdrawPayment.getCreateTime()));
        jOrder.put("remark", "收益");
        getOrderDTOS.add(jOrder);
        String[] headers = {"序号", "姓名", "手机号", "身份证号", "银行卡号", "发放金额", "发生时间", "备注"};
        String[] fieldNames = {"number", "name", "phone", "idCard", "accountNo", "amt", "time", "remark"};
        ExportExcelUtils.exportExcelByxls(orderNo, headers, fieldNames, getOrderDTOS, HttpHolderUtil.getRequest(), HttpHolderUtil.getResponse());
    }

    /**
     * 是否在提现负债名单
     *
     * @param userBaseId
     * @return
     */
    private boolean isWithdrawDebitFlag(String userBaseId) {

        FundWithdrawDebitListExample fundWithdrawDebitListExample = new FundWithdrawDebitListExample();
        fundWithdrawDebitListExample.createCriteria()
                .andUserBaseIdEqualTo(userBaseId)
                .andStatusEqualTo(FundWithdrawDebitListEnum.DebitStatusEnum.STATUS_100.getCode())
                .andIsDelNotEqualTo(DeleteFlag.TRUE);
        List<FundWithdrawDebitList> fundWithdrawDebitListList =
                fundWithdrawDebitListMapper.selectByExample(fundWithdrawDebitListExample);

        return !CollectionUtils.isEmpty(fundWithdrawDebitListList);
    }

    /**
     * 用户是否是未实名状态
     *
     * @param userBaseId 用户ID
     * @return 是true
     */
    private boolean userUnCheck(String userBaseId) {
        UserBase userBase = userBaseMapper.selectByPrimaryKey(userBaseId);
        return Short.valueOf(Constant.NO).equals(userBase.getCheckStatus());
    }
}
